package base.generic.demo10;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.junit.Test;

import com.alibaba.fastjson.JSONObject;

/**
 * Java中  <?  extends T> 和  <?  super T>
 * <? extends T> T表示类型的上界，？表示的参数化类型可能是T 或是 T的子类;
 * <? super T> T表示类型下界,？表示的参数化类型是T类型的超类型（父类型），直至Object;
 *
 * extends 用于返回类型限定，不能用于参数类型限定（换句话说：?  extends xxx 只能用于方法返回类型限定，
 * jdk能够确定此类的最小继承边界为xxx，只要是这个类的子类都能接收，但是传入参数无法确定具体类型，只能接受null的传入）。
 *
 * super 用于参数类型限定，不能用于返回类型限定（换句话说：? supper xxx 只能用于方法传参，
 * 因为jdk能够确定传入为xxx的子类，返回只能用Object类接收）。
 *
 */
public class TestCase {

    @Test
    public void testCase1(){
//        List<Father> list0 = new ArrayList<Son>();//compile error,没有任何地方表明Son是Father的父子关系判定。泛型也不会。
//        list0.add(new Son());//泛型只会说明list0只能存储Father类型，存Father子类是可以的。

        List<?> list1 = new ArrayList<Father>();
//        list1.add(new Father());//compile error，?泛型代表可以存储任何对象，你这里明确存Father对象是不行的，add方法只能存null，null代表任何空对象
        list1.add(null);
        list1 = getGenericList();//虽然不能给list1直接add添加对象，但是可以接收外部方法返回的泛型列表
        System.out.println(list1);//[Human(name=大明, age=28)]
    }

    public static List<?> getGenericList(){
        List<Father> fathers = new ArrayList<>();
        fathers.add(new Father("大明", 28));
        return fathers;
    }

    /**
     * ？标注上限，后add() 方法不可用，？代表任何类型，你不能通过add()只添加一种具体类型，
     * 但你可以接收外部方法返回的泛型列表。
     * 换句话说，就是add方法内部在添加对象时，肯定是做了类型校验。
     */
    @Test
    public void testCase2(){
        List<? extends Father> list = new ArrayList<>();
//        list.add(new Father());//compile error
//        list.add(new Son());//compile error
        list = getFatherList();
        System.out.println(JSONObject.toJSONString(list));
        for (Iterator<?> iterator = list.iterator(); iterator.hasNext();) {
            Son son = (Son) iterator.next();
            System.out.println(JSONObject.toJSONString(son));
        }
    }

//  public static List<Father> getFatherList(){ //compile error,没有地方能够说明返回的List<Son>类型需要做往List<Father>的判断
    public static List<? extends Father> getFatherList(){
        List<Son> list = new ArrayList<Son>();
        list.add(new Son("小明", 2));
        return list;
    }

    @Test
    public void testCase3(){
        /**
         * ?标注下界,？是Father的父类，可用于参数类型限定，不能用于返回类型限定，
         * 因为我们还不知道具体的是哪个父类，Father的父类很多。
         */
        //compile Success,声明只能为Father或其父类泛型，但add()只能存Father及其子类,而不能是Human 类型
        List<? super Father> list1 = new ArrayList<Human>();
//        list1.add(new Human());//compile error,?是Father父类，你存入一个具体的Human这个父类是不行的。但你可以往里面存入Father的子类。
        list1.add(new Son("小明",2));
        list1.add(new Father("大明", 28));
        System.out.println(list1);//[Human(name=小明, age=2), Human(name=大明, age=28)]
    }

    @Test
    public void testCase4(){
        List<? super Father> list = new ArrayList<Father>();
        list.add(new Father("大明",28));
        list = getSuperFatherList();
        System.out.println(list);
    }

    public static List<? super Father> getSuperFatherList(){
        List<Human> list = new ArrayList<Human>();
        list.add(new Father("大明",28));
        list.add(new Son("小明", 2));
        list.add(new Daughter("小艾", 1));
        return list;
    }
}
